package com.xms.schema.service.attribute;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xms.core.config.FinalValueDefaults;
import com.xms.core.config.SystemEntityNames;
import com.xms.core.exception.XmsException;
import com.xms.datacore.IMetadataProvider;
import com.xms.datacore.service.CreaterService;
import com.xms.schema.core.AttributeDescriptor;
import com.xms.schema.core.AttributeTypeIds;
import com.xms.schema.core.RelationShipType;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.entity.RelationShip;
import com.xms.schema.extension.AttributeExt;
import com.xms.schema.service.entity.IEntityFinderService;
import com.xms.schema.service.optionset.IOptionSetCreaterService;
import com.xms.schema.service.relationship.IRelationShipCreaterService;
import com.xms.schema.service.relationship.IRelationShipFinderService;
import com.xms.schema.service.stringmap.IStringMapCreaterService;
import com.xms.utils.CollectionUtil;
import com.xms.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * AttributeCreaterService
 * </p>
 *
 * @author migo
 * @since 2021/9/2
 */
@CacheConfig(cacheNames = "schema.attribute", keyGenerator = "CacheKeyGenerator")
@Service
public class AttributeCreaterService extends CreaterService<Attribute> implements IAttributeCreaterService {
    private IStringMapCreaterService _stringMapCreaterService;
    private IRelationShipFinderService _relationShipFinderService;
    private IRelationShipCreaterService _relationShipCreaterService;
    private IEntityFinderService _entityFinderService;
    private IOptionSetCreaterService _optionSetCreaterService;
    private IMetadataProvider _metadataProvider;
    private IAttributeFinderService _attributeFinderService;
    private IAttributeDependency _attributeDependency;

    @Autowired
    public void AttributeCreaterService(IStringMapCreaterService stringMapCreaterService
            , IRelationShipFinderService relationShipFinderService
            , IRelationShipCreaterService relationShipCreaterService
            , IEntityFinderService entityFinderService
            , IMetadataProvider metadataProvider
            , IAttributeFinderService attributeFinderService
            , IOptionSetCreaterService optionSetCreaterService
            , IAttributeDependency attributeDependency) {
        _stringMapCreaterService = stringMapCreaterService;
        _relationShipFinderService = relationShipFinderService;
        _relationShipCreaterService = relationShipCreaterService;
        _entityFinderService = entityFinderService;
        _metadataProvider = metadataProvider;
        _attributeFinderService = attributeFinderService;
        _optionSetCreaterService = optionSetCreaterService;
        _attributeDependency = attributeDependency;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean create(Attribute entity) throws SQLException, XmsException {
        AttributeDescriptor attributeDescriptor = null;
        //选项类型
        if (AttributeExt.typeIsPickList(entity)) {
            if (entity.getOptionset() != null) {
                attributeDescriptor = new AttributeDescriptor(entity, entity.getOptionset(), entity.getOptionset().getItems());
            }
        }
        //bit类型
        else if (AttributeExt.typeIsBit(entity)) {
            attributeDescriptor = new AttributeDescriptor(entity, entity.getPicklists());
        }
        if (attributeDescriptor == null) {
            attributeDescriptor = new AttributeDescriptor(entity);
        }

        return this.create(attributeDescriptor);
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean createMany(Collection<Attribute> entityList) throws SQLException, XmsException {
        if (CollectionUtil.notEmpty(entityList)) {
            for (Attribute attribute : entityList) {
                this.create(attribute);
            }
        }
        return true;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean create(AttributeDescriptor attributeDescriptor) throws SQLException, XmsException {
        Attribute entity = attributeDescriptor.attribute;
        //检查名称是否已存在
        Attribute existsAttr = _attributeFinderService.getByName(entity.getEntityid(), entity.getName());
        if (existsAttr != null) {
            throw new XmsException("字段名称已存在: " + existsAttr.getName() + "(" + existsAttr.getLocalizedname() + ")");
        }
        if (StringUtil.isEmpty(entity.getDefaultvalue())
                && (AttributeExt.typeIsBit(entity) || AttributeExt.typeIsDecimal(entity) || AttributeExt.typeIsFloat(entity)
                || AttributeExt.typeIsInt(entity) || AttributeExt.typeIsMoney(entity) || AttributeExt.typeIsSmallInt(entity)
                || AttributeExt.typeIsSmallMoney(entity) || AttributeExt.typeIsState(entity) || AttributeExt.typeIsStatus(entity))) {
            entity.setDefaultvalue("0");
        }
        Entity parentEntity = _entityFinderService.getById(entity.getEntityid());
        boolean success = super.save(entity);
        if (success) {
            //这里直接从数据库中取
            List<Attribute> attributes = _attributeFinderService.list(new LambdaQueryWrapper<Attribute>().eq(Attribute::getEntityid, entity.getEntityid()));
            //List<Attribute> attributes = _attributeFinderService.getByEntityId(entity.getEntityid());
            //如果事务未提交，这里需要添加当前记录
            if(!attributes.stream().anyMatch(x->x.getAttributeid().equals(entity.getAttributeid()))){
                attributes.add(entity);
            }
            List<RelationShip> relationships = _relationShipFinderService.list(new LambdaQueryWrapper<RelationShip>()
            .eq(RelationShip::getReferencingentityid, entity.getEntityid()));
            //List<RelationShip> relationships = _relationShipFinderService.getByReferencingEntityId(entity.getEntityid());
            //引用类型
            if (AttributeExt.typeIsLookUp(entity) || AttributeExt.typeIsOwner(entity) || AttributeExt.typeIsCustomer(entity)) {
                Entity referencing = _entityFinderService.getById(entity.getEntityid());
                Attribute referenced = _attributeFinderService.getPrimaryKey(entity.getReferencedentityid());
                RelationShip relationShip = new RelationShip();
                relationShip.setName("lk_" + referencing.getName() + "_" + entity.getName());
                relationShip.setRelationshiptype(RelationShipType.ManyToOne.value());
                relationShip.setReferencingattributeid(entity.getAttributeid());
                relationShip.setReferencingattributename(entity.getName());
                relationShip.setReferencingentityid(entity.getEntityid());
                relationShip.setReferencingentityname(entity.getEntityname());
                relationShip.setReferencedattributeid(referenced.getAttributeid());
                relationShip.setReferencedattributename(referenced.getName());
                relationShip.setReferencedentityid(referenced.getEntityid());
                relationShip.setReferencedentityname(referenced.getEntityname());
                relationShip.setCascadelinkmask(parentEntity.getParententityid() != null ? 1 : 2);
                relationShip.setCascadeassign(parentEntity.getParententityid() != null ? 1 : 4);
                relationShip.setCascadedelete(parentEntity.getParententityid() != null ? 1 : 4);
                relationShip.setCascadeshare(parentEntity.getParententityid() != null ? 1 : 4);
                relationShip.setCascadeunshare(parentEntity.getParententityid() != null ? 1 : 4);
                relationShip.setIscustomizable(parentEntity.getParententityid() == null);
                _relationShipCreaterService.create(relationShip);
                relationships.add(relationShip);
            }
            //选项类型
            else if (AttributeExt.typeIsPickList(entity)) {
                if (attributeDescriptor.optionset != null && !attributeDescriptor.optionset.getIspublic()) {
                    _optionSetCreaterService.create(attributeDescriptor.optionset, attributeDescriptor.optionsetdetails);
                }
            }
            //bit类型
            else if (AttributeExt.typeIsBit(entity)) {
                _stringMapCreaterService.createMany(attributeDescriptor.stringmaps);
            }
            //add table column
            _metadataProvider.addColumn(entity);
            //update db view
            _metadataProvider.alterView(parentEntity, attributes, relationships);
            //依赖项
            _attributeDependency.create(entity);
        }
        return success;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean createDefaultAttributes(Entity entity, DefaultAttributeDatas defaultAttributeDatas) throws XmsException, SQLException {
        boolean result;
        for (Attribute attribute : defaultAttributeDatas.attributes) {
            result = super.create(attribute);
            //依赖项
            _attributeDependency.create(attribute);
        }
        //新建字段选项
        Attribute stateCodeAttr = defaultAttributeDatas.attributes.stream().filter(n -> n.getName().equalsIgnoreCase("statecode")).findFirst().orElse(null);
        if (stateCodeAttr != null) {
            result = _stringMapCreaterService.createMany(defaultAttributeDatas.picklists);
        }
        Attribute statusCodeAttr = defaultAttributeDatas.attributes.stream().filter(n -> n.getName().equalsIgnoreCase("statuscode")).findFirst().orElse(null);
        if (statusCodeAttr != null) {
            result = _optionSetCreaterService.create(statusCodeAttr.getOptionset());
        }
        //创建关系
        result = _relationShipCreaterService.createMany(defaultAttributeDatas.relationships);

        return result;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean createOwnerAttributes(Entity entity) throws XmsException, SQLException {
        List<Attribute> existAttributes = _attributeFinderService.getByName(entity.getEntityid(), Arrays.asList("ownerid", "owneridtype", "owningbusinessunit"));
        if (existAttributes != null && existAttributes.size() == 3) {
            return true;
        }
        Attribute systemUserPrimaryKey = _attributeFinderService.getPrimaryKey(SystemEntityNames.SystemUser);
        Attribute businessUnitPrimaryKey = _attributeFinderService.getPrimaryKey(SystemEntityNames.BusinessUnit);
        List<Attribute> attrList = new LinkedList<>();
        if (!existAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase("ownerid"))) {
            Attribute ownerIdAttr = new Attribute();
            ownerIdAttr.setAttributeid(UUID.randomUUID());
            ownerIdAttr.setEntityid(entity.getEntityid());
            ownerIdAttr.setName("ownerid");
            ownerIdAttr.setLocalizedname("所有者");
            ownerIdAttr.setAttributetypename(AttributeTypeIds.OWNER);
            ownerIdAttr.setReferencedentityid(systemUserPrimaryKey.getEntityid());
            ownerIdAttr.setReferencedentityname(SystemEntityNames.SystemUser);
            ownerIdAttr.setEntityname(entity.getName());
            ownerIdAttr.setIsnullable(false);
            ownerIdAttr.setIsrequired(true);
            ownerIdAttr.setLogenabled(false);
            ownerIdAttr.setIscustomizable(false);
            ownerIdAttr.setIscustomfield(false);
            ownerIdAttr.setAuthorizationenabled(false);
            ownerIdAttr.setIsprimaryfield(false);
            ownerIdAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
            ownerIdAttr.setCreatedon(LocalDateTime.now());
            attrList.add(ownerIdAttr);
        }
        if (!existAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase("owneridtype"))) {
            Attribute ownerIdTypeAttr = new Attribute();
            ownerIdTypeAttr.setAttributeid(UUID.randomUUID());
            ownerIdTypeAttr.setEntityid(entity.getEntityid());
            ownerIdTypeAttr.setName("owneridtype");
            ownerIdTypeAttr.setLocalizedname("所有者类型");
            ownerIdTypeAttr.setAttributetypename(AttributeTypeIds.INT);
            ownerIdTypeAttr.setEntityname(entity.getName());
            ownerIdTypeAttr.setIsnullable(false);
            ownerIdTypeAttr.setIsrequired(true);
            ownerIdTypeAttr.setLogenabled(false);
            ownerIdTypeAttr.setIscustomizable(false);
            ownerIdTypeAttr.setIscustomfield(false);
            ownerIdTypeAttr.setAuthorizationenabled(false);
            ownerIdTypeAttr.setIsprimaryfield(false);
            ownerIdTypeAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
            ownerIdTypeAttr.setCreatedon(LocalDateTime.now());
            attrList.add(ownerIdTypeAttr);
        }
        if (!existAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase("owningbusinessunit"))) {
            Attribute owningBusinessUnitAttr = new Attribute();
            owningBusinessUnitAttr.setAttributeid(UUID.randomUUID());
            owningBusinessUnitAttr.setEntityid(entity.getEntityid());
            owningBusinessUnitAttr.setName("owningbusinessunit");
            owningBusinessUnitAttr.setLocalizedname("所有者部门");
            owningBusinessUnitAttr.setAttributetypename(AttributeTypeIds.LOOKUP);
            owningBusinessUnitAttr.setReferencedentityid(businessUnitPrimaryKey.getEntityid());
            owningBusinessUnitAttr.setReferencedentityname(SystemEntityNames.BusinessUnit);
            owningBusinessUnitAttr.setEntityname(entity.getName());
            owningBusinessUnitAttr.setIsnullable(true);
            owningBusinessUnitAttr.setIsrequired(true);
            owningBusinessUnitAttr.setLogenabled(false);
            owningBusinessUnitAttr.setIscustomizable(false);
            owningBusinessUnitAttr.setIscustomfield(false);
            owningBusinessUnitAttr.setAuthorizationenabled(false);
            owningBusinessUnitAttr.setIsprimaryfield(false);
            owningBusinessUnitAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
            owningBusinessUnitAttr.setCreatedon(LocalDateTime.now());
            attrList.add(owningBusinessUnitAttr);
        }
        for (Attribute attr : attrList) {
            this.create(new AttributeDescriptor(attr));
        }
        return true;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean createWorkFlowAttributes(Entity entity) throws XmsException, SQLException {
        List<Attribute> existAttributes = _attributeFinderService.getByName(entity.getEntityid(), Arrays.asList("workflowid", "processstate"));
        if (existAttributes != null && existAttributes.size() == 2) {
            return true;
        }
        Attribute workFlowPrimaryKey = entity.getWorkflowenabled() ?
                _attributeFinderService.getPrimaryKey(SystemEntityNames.WorkFlow) : null;
        List<Attribute> attributes = new ArrayList<>();
        if (!existAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase("workflowid"))) {
            Attribute workflowIdAttr = new Attribute();
            workflowIdAttr.setAttributeid(UUID.randomUUID());
            workflowIdAttr.setEntityid(entity.getEntityid());
            workflowIdAttr.setName("workflowid");
            workflowIdAttr.setLocalizedname("审批流");
            workflowIdAttr.setAttributetypename(AttributeTypeIds.LOOKUP);
            workflowIdAttr.setReferencedentityid(workFlowPrimaryKey.getEntityid());
            workflowIdAttr.setReferencedentityname(SystemEntityNames.WorkFlow);
            workflowIdAttr.setEntityname(entity.getName());
            workflowIdAttr.setIsnullable(true);
            workflowIdAttr.setIsrequired(false);
            workflowIdAttr.setLogenabled(false);
            workflowIdAttr.setIscustomizable(false);
            workflowIdAttr.setIscustomfield(false);
            workflowIdAttr.setAuthorizationenabled(false);
            workflowIdAttr.setIsprimaryfield(false);
            workflowIdAttr.setCreatedon(LocalDateTime.now());
            workflowIdAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
            attributes.add(workflowIdAttr);
        }

        if (!existAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase("processstate"))) {
            Attribute processStateAttr = new Attribute();
            processStateAttr.setAttributeid(UUID.randomUUID());
            processStateAttr.setEntityid(entity.getEntityid());
            processStateAttr.setName("processstate");
            processStateAttr.setLocalizedname("审批状态");
            processStateAttr.setAttributetypename(AttributeTypeIds.PICKLIST);
            processStateAttr.setEntityname(entity.getName());
            processStateAttr.setIsnullable(true);
            processStateAttr.setIsrequired(false);
            processStateAttr.setLogenabled(false);
            processStateAttr.setIscustomizable(false);
            processStateAttr.setIscustomfield(false);
            processStateAttr.setAuthorizationenabled(false);
            processStateAttr.setIsprimaryfield(false);
            processStateAttr.setDefaultvalue("-1");
            processStateAttr.setOptionsetid(UUID.fromString("00000000-0000-0000-0000-000000000001"));
            processStateAttr.setCreatedon(LocalDateTime.now());
            processStateAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
            attributes.add(processStateAttr);
        }
        for (Attribute attr : attributes) {
            this.create(new AttributeDescriptor(attr));
        }
        return true;
    }
}
